<?php
/**
 * Model class
 *
 * @access 	public
 * @author 	Salvatore Borrelli
 * @copyright	ResMania 2011 all rights reserved.
 * @version	1.0
 * @link		http://developer.resmania.com/api
 * @since  	11-2011
 */
class RM_UnitPriceBands extends RM_Model_Flexible
{
    /* Database meta information */
    const F_ID = "id";
    const F_UNIT_ID = "unit_id";
    const F_START_DATETIME = "start_datetime";
    const F_END_DATETIME = "end_datetime";
    const F_BANDS_PRICES = "bands_prices";
    const BP_BAND_ID = "band_id";
    const BP_BAND_PRICE = "band_price";
    const BP_PREFIX = "band_";
    
    protected $_name = 'rm_unit_price_bands';
    /**
     * Returns the total number of prices configured for a given unit
     * @param unit the source unit
     * @return the requested total number of prices
     */
    public function getUnitCount($unit) {
        $select = $this->select();
        $select->from($this, array('count(*) as count'));
        $rows = $this->fetchAll($select);
        return($rows[0]->count);
    }
    /**
     * Returns all prices for unit
     * @param [int] unitId the unit identifier
     * @param [string] $order the name of the field for ordering
     * @param [int] $count the number of records to load, or <code>0</code> to load all the available records
     * @param [int] $offset the starting field index (0-based)
     * @return [RM_Unit_Row $unit[]] the list of unit prices
     */
    public function getUnitPrices($unitId, $order = 'id', $count = 0, $offset = 0)
    {
        $select = $this->select();
        $select->where("unit_id=$unitId");
        $select->order($order);
        if ($count>0){
            $select->limit($count, $offset);
        }
        return $this->fetchAll($select);
    }
    /**
     * Returns the set of unit prices on a given unit in a suitable format for visualization
     * @param [int] unitId the unit identifier
     * @param [string] $order the name of the field for ordering
     * @param [int] $count the number of records to load, or <code>0</code> to load all the available records
     * @param [int] $offset the starting field index (0-based)
     * @return [array] the unit prices map, ready to be sent to the client for visualization
     */
    public function getExpandedUnitPrices($unitId, $order = 'id', $count = 0, $offset = 0) {
        $pricesMap = array();
        try {
            // gets the unit prices from the database
            $res = $this->getUnitPrices($unitId, $order, $count, $offset);
            $pricesEntry = array();
            $bandsPrices = null;
            foreach($res as $row) {
                // copy the common fields to the entry
                $pricesEntry[self::F_ID] = $row[self::F_ID];
                $pricesEntry[self::F_UNIT_ID] = $row[self::F_UNIT_ID];
                $pricesEntry[self::F_START_DATETIME] = $row[self::F_START_DATETIME];
                $pricesEntry[self::F_END_DATETIME] = $row[self::F_END_DATETIME];
                $bandsPrices = $row[self::F_BANDS_PRICES];
                if (!empty($bandsPrices)) {
                    // add the configured band prices to the map
                    $bps = json_decode($bandsPrices, true);
                    foreach($bps as $bandId=>$bandPrice) {
                        $pricesEntry[$bandId] = $bandPrice;
                    }
                }
                // add this element to the map
                $pricesMap[] = $pricesEntry;
            }
        }
        catch(Exception $e) {
            RM_Log::toLog("failed to get prices for unit $unitId", $e);
        }
        return $pricesMap;
    }
    /**
     * Maps a unit prices grid row to the database structure
     * @param row the source row
     * @return the prepared row
     */
    public static function gridRowToDb($row) {
        $dbRow = array();
        // copy the common fields to the database row
        $dbRow[self::F_ID] = $row[self::F_ID];
        $dbRow[self::F_UNIT_ID] = $row[self::F_UNIT_ID];
        if (array_key_exists(self::F_START_DATETIME, $row)) {
            $dbRow[self::F_START_DATETIME] = $row[self::F_START_DATETIME];
        }
        else {
            // set the current date/time (ISO 8601) as default
            $dt = new DateTime();
            $dbRow[self::F_START_DATETIME] = $dt->format('c');
        }
        if (array_key_exists(self::F_END_DATETIME, $row)) {
            $dbRow[self::F_END_DATETIME] = $row[self::F_END_DATETIME];
        }
        else {
            // set a default end date (ISO 8601)
            $dt = new RM_Date();
            $dbRow[self::F_END_DATETIME] = $dt->dateAdd(Date("Y-m-d"),3650);
        }
        // builds the band prices array
        $len = strlen(self::BP_PREFIX);
        $bandPrices = array();
        foreach(array_keys($row) as $key) {
            if (substr($key, 0, $len) == self::BP_PREFIX) {
                // add the element to the array
                $bandPrices[$key] = (!empty($row[$key]) ? floatval($row[$key]) : 0);
            }
        }
        // set the brand prices database value
        $dbRow[self::F_BANDS_PRICES] = json_encode($bandPrices);
        return $dbRow;
    }
    public function getLastPriceBandDate($unit_id){
        $sql = "SELECT `end_datetime` FROM `rm_unit_price_bands` WHERE `unit_id`=1 ORDER BY `end_datetime` DESC LIMIT 1";
        return $this->_getBySQL($sql)->current();
    }
    /**
     * Returns the lowest price of a unit over a given period
     *
     * @param $information RM_PriceBands_Information - information object,
     * contains all needed information about unit reservation:
     * unit,
     * start date,
     * end date,
     * number of persons
     * etc.
     *
     * @return float
     */
    function getLowestPrice($information) {
        $sql = "select * from rm_unit_price_bands where unit_id = '".$information->getUnit()->id."'";
        if ($information->getPeriod() !== null) {
            $startDatetime = $information->getPeriod()->getStart()->toMySQL();
            $endDatetime = $information->getPeriod()->getEnd()->toMySQL();
            $sql.= "
                AND (
                    (UNIX_TIMESTAMP(start_datetime) <= UNIX_TIMESTAMP('$startDatetime') && UNIX_TIMESTAMP(end_datetime) >= UNIX_TIMESTAMP('$startDatetime') )
                     OR
                    (UNIX_TIMESTAMP(start_datetime) <= UNIX_TIMESTAMP('$endDatetime') && UNIX_TIMESTAMP(end_datetime) >= UNIX_TIMESTAMP('$endDatetime') )
                     OR
                    (UNIX_TIMESTAMP(start_datetime) >= UNIX_TIMESTAMP('$startDatetime') && UNIX_TIMESTAMP(end_datetime) <= UNIX_TIMESTAMP('$endDatetime') )
                )
            ";
        } else {
            $sql.= "
                AND UNIX_TIMESTAMP(end_datetime) >= ".time()."
            ";
        }
        $rows = $this->_getBySQL($sql);
        $lowest = 999999;
        $bandsPrices = null;
        $bandsMin = 0;
        foreach ($rows as $row) {
            $bandsPrices = json_decode($row->bands_prices, true);
            if (is_array($bandsPrices)){
                $bandsMin = min($bandsPrices);
            }
            if ($bandsMin>0 && $bandsMin<$lowest) {
                $lowest = $bandsMin;
            }
        }
        if ($lowest == 999999) {
            $lowest = 0;
        }
        return $lowest;
    }
    public function getHighestPrice(){
        $highest = 0;
        $rows = $this->fetchAll();
        $bandsPrices = null;
        $bandsMax = 0;
        foreach($rows as $row) {
            $bandsPrices = json_decode($row->bands_prices);
            $bandsMax = max($bandsPrices);
            if ($bandsMax>$highest) {
                $highest = $bandsMax;
            }
        }
        return $highest;
    }
    /**
     * This method will returns all units prices are in a given range in the specified period
     * @param float $from the minimum price
     * @param float $to the maximum price
     * @param RM_Reservation_Period $period the reservation period
     * @return Zend_Db_Table_Rowset_Abstract
     */
    public function getByPriceRange($from, $to, $period = null){
        $sql = "select * from $this->_name";
        if ($period !== null) {
            $sql .= " and
                ((
                    unix_timestamp(start_datetime)<unix_timestamp('".$period->getEnd()->toMySQL()."')
                        and
                    unix_timestamp(end_datetime)>=unix_timestamp('".$period->getEnd()->toMySQL()."')
                ) or (
                    unix_timestamp(start_datetime)>unix_timestamp('".$period->getStart()->toMySQL()."')
                        and
                    unix_timestamp(end_datetime)<=unix_timestamp('".$period->getStart()->toMySQL()."')
                ) or (
                    unix_timestamp(start_datetime)>unix_timestamp('".$period->getStart()->toMySQL()."')
                        and
                    unix_timestamp(end_datetime)<=unix_timestamp('".$period->getEnd()->toMySQL()."')
                ))
            ";
        }
        $rows = $this->_getBySQL($sql);
        // check prices
        $inRange = array();
        foreach($rows as $row) {
            $bandsPrices = json_decode($row->bands_prices);
            $bandsMax = max($bandsPrices);
            $bandsMin = min($bandsPrices);
            if ($bandsMin>=$from && $bandsMax<=$to) {
                // unit in range
                $inRange[] = $row;
            }
        }
        return $inRange;
    }
    /**
     * @param RM_Reservation_Period $period
     * @return array array with unit ids
     */
    public function getByMinPeriod(RM_Reservation_Period $period){
        // does not apply to this module
        return array();
    }
}